/*
 * $RCSfile: SeismoNavMouseMode.java,v $
 * $Revision: 1.2 $
 * $Date: 2006/04/01 20:24:28 $
 *
 * Copyright (c) 2001-2006: University of Piraeus.
 * People involved: Asst. Prof. Yannis Theodoridis,
 * PhD student G. Marketos and researcher Dr. I.S. Kalogeras.
 */

package seismosurfer.event;

import java.awt.Cursor;
import java.awt.event.MouseEvent;

import com.bbn.openmap.MapBean;
import com.bbn.openmap.event.NavMouseMode;
import com.bbn.openmap.proj.Proj;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;

/**
 * An extension to the NavMouseMode to handle mouse clicks and mouse drags.
 *
 */
public class SeismoNavMouseMode extends NavMouseMode {

    private static final long serialVersionUID = -8619754686885136474L;

    /**
     * Construct a SeismoNavMouseMode. Sets the ID of the mode to the modeID, the
     * consume mode to true, and the cursor to the crosshair.
     */
    public SeismoNavMouseMode() {
        this(true);
    }

    /**
     * Construct a SeismoNavMouseMode. Lets you set the consume mode. If the events
     * are consumed, then a MouseEvent is sent only to the first
     * MapMouseListener that successfully processes the event. If they are not
     * consumed, then all of the listeners get a chance to act on the event.
     * 
     * @param shouldConsumeEvents
     *            the mode setting.
     */
    public SeismoNavMouseMode(boolean shouldConsumeEvents) {
        super(shouldConsumeEvents);
        // override the super class cursor
        setModeCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }

    /**
     * Handle a mouseReleased MouseListener event. If there was no drag events,
     * or if there was only a small amount of dragging between the occurence of
     * the mousePressed and this event, then recenter the map. Otherwise we get
     * the second corner of the navigation rectangle and try to figure out the
     * best scale and location to zoom in to, based on that rectangle.
     * 
     * @param e  MouseEvent to be handled
     */
    public void mouseReleased(MouseEvent e) {
        if (Debug.debugging("mousemode")) {
            Debug.output(getID() + "|NavMouseMode.mouseReleased()");
        }
        Object obj = e.getSource();

        mouseSupport.fireMapMouseReleased(e);

        if (!(obj instanceof MapBean) || !autoZoom || point1 == null) {
            return;
        }

        final MapBean map = (MapBean) obj;
        Projection projection = map.getProjection();
        Proj p = (Proj) projection;

        synchronized (this) {
            point2 = e.getPoint();
            final int dx = Math.abs(point2.x - point1.x);
            final int dy = Math.abs(point2.y - point1.y);

            // Don't bother redrawing if the rectangle is too small
            if ((dx < 5) || (dy < 5)) {
                // clean up the rectangle, since point2 has the old
                // value.
                paintRectangle(map, point1, point2);

                // If rectangle is too small in both x and y then
                // recenter the map
                if ((dx < 5) && (dy < 5)) {
                    boolean shift = e.isShiftDown();
                    boolean control = e.isControlDown();
                    if (control) {
                        if (shift) {
                            p.setScale(p.getScale() * 2.0f);
                        } else {
                            p.setScale(p.getScale() / 2.0f);
                        }
                    }

                    // reset the points here so the point doesn't get
                    // rendered on the repaint.
                    point1 = null;
                    point2 = null;

                    // p.setCenter(llp);
                    // map.setProjection(p);
                }
                return;
            }

            // Figure out the new scale
            float newScale = com.bbn.openmap.proj.ProjMath.getScale(point1,
                    point2, projection);

            // Figure out the center of the rectangle
            int centerx = Math.min(point1.x, point2.x) + dx / 2;
            int centery = Math.min(point1.y, point2.y) + dy / 2;
            com.bbn.openmap.LatLonPoint center = projection.inverse(centerx,
                    centery);

            // Fire events on main map to change view to match rect1
            // Debug.output("point1: " +point1);
            // Debug.output("point2: " +point2);
            // Debug.output("Centerx: " +centerx +
            // " Centery: " + centery);
            // Debug.output("New Scale: " + newScale);
            // Debug.output("New Center: " +center);

            // Set the parameters of the projection and then set
            // the projection of the map. This way we save having
            // the MapBean fire two ProjectionEvents.
            p.setScale(newScale);
            p.setCenter(center);

            // reset the points here so the point doesn't get rendered
            // on the repaint.
            point1 = null;
            point2 = null;

            map.setProjection(p);
        }

    }

}
